package com.netposa.datawarehouse.aggregator.client.fallback;

import com.alibaba.fastjson.JSON;
import com.github.rholder.retry.Attempt;
import com.github.rholder.retry.RetryException;
import com.github.rholder.retry.RetryListener;
import com.github.rholder.retry.Retryer;
import com.github.rholder.retry.RetryerBuilder;
import com.github.rholder.retry.StopStrategies;
import com.github.rholder.retry.WaitStrategies;
import com.netposa.appwebres.common.WebResInfo;
import com.netposa.datawarehouse.aggregator.client.BodyServiceClient;
import com.netposa.datawarehouse.aggregator.client.FaceServiceClient;
import com.netposa.datawarehouse.aggregator.client.NonmotorServiceClient;
import com.netposa.datawarehouse.aggregator.client.VehicleServiceClient;
import com.netposa.datawarehouse.aggregator.client.WifiServiceClient;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.util.List;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit;
import javax.annotation.PostConstruct;
import okhttp3.MediaType;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.RequestBody;
import okhttp3.Response;
import okio.BufferedSink;
import org.apache.commons.lang3.RandomUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.client.ServiceInstance;
import org.springframework.cloud.client.discovery.DiscoveryClient;
import org.springframework.context.annotation.Primary;
import org.springframework.stereotype.Component;
import org.springframework.web.bind.annotation.RequestMethod;

@Component
@Primary
public class BaseServiceClientFallback implements FaceServiceClient, BodyServiceClient, VehicleServiceClient, WifiServiceClient, NonmotorServiceClient {
   private static final Logger log = LoggerFactory.getLogger(BaseServiceClientFallback.class);
   @Autowired
   private DiscoveryClient discoveryClient;
   @Autowired
   private OkHttpClient okHttpClient;
   private Retryer retryer;
   private static final String BODY_SERVICE = "body-service";
   private static final String FACE_SERVICE = "face-service";
   private static final String VEHICLE_SERVICE = "vehicle-service";
   private static final String WIFI_SERVICE = "wifi-service";

   @PostConstruct
   public void init() {
      this.retryer = RetryerBuilder.newBuilder().retryIfRuntimeException().withRetryListener(new RetryListener() {
         public void onRetry(Attempt attempt) {
            BaseServiceClientFallback.log.debug("Retry[times={}s delay={}ms hasException={} causeBy={} hasResult={} ]", new Object[]{attempt.getAttemptNumber(), attempt.getDelaySinceFirstAttempt(), attempt.hasException(), attempt.hasException() ? attempt.getExceptionCause().getMessage() : "", attempt.hasResult()});
         }
      }).withWaitStrategy(WaitStrategies.fixedWait(50L, TimeUnit.MILLISECONDS)).withStopStrategy(StopStrategies.stopAfterAttempt(5)).build();
   }

   private String serviceAddress(String serviceId) throws ServiceInstanceFetchException {
      try {
         return (String)this.retryer.call(() -> {
            List serviceInstances = this.discoveryClient.getInstances(serviceId);
            if (serviceInstances.isEmpty()) {
               log.warn("Not found {} service instance .", serviceId);
               throw new RuntimeException("Not found " + serviceId);
            } else {
               ServiceInstance serviceInstance = (ServiceInstance)serviceInstances.get(RandomUtils.nextInt(0, serviceInstances.size()));
               return String.format("http://%s:%d", serviceInstance.getHost(), serviceInstance.getPort());
            }
         });
      } catch (RetryException | ExecutionException var3) {
         throw new ServiceInstanceFetchException();
      }
   }

   private String call(Request request) throws IOException {
      Response response = null;

      String var3;
      try {
         response = this.okHttpClient.newCall(request).execute();
         if (!response.isSuccessful()) {
            var3 = null;
            return var3;
         }

         var3 = response.body().string();
      } finally {
         try {
            if (response != null) {
               response.close();
            }
         } catch (Exception var11) {
         }

      }

      return var3;
   }

   public WebResInfo getBodyOriginalByIds(BodyCondition condition) {
      return this.handler(RequestMethod.POST, "body-service", "/body/get_by_recordIds", JSON.toJSONString(condition));
   }

   public WebResInfo getBodyOriginalList(String condition) {
      return this.handler(RequestMethod.POST, "body-service", "/body/list", condition);
   }

   public WebResInfo countBody(String condition) {
      return this.handler(RequestMethod.POST, "body-service", "/body/count", condition);
   }

   public WebResInfo getFaceOriginalByIds(FaceCondition condition) {
      return this.handler(RequestMethod.POST, "face-service", "/face/get_by_recordIds", JSON.toJSONString(condition));
   }

   public WebResInfo getFaceOriginalByCollectionId(FaceCondition condition) {
      return this.handler(RequestMethod.POST, "face-service", "/face/get_by_collectionId", JSON.toJSONString(condition));
   }

   public WebResInfo getFaceOriginalList(String condition) {
      return this.handler(RequestMethod.POST, "face-service", "/face/list", condition);
   }

   public WebResInfo countFace(String condition) {
      return this.handler(RequestMethod.POST, "face-service", "/face/count", condition);
   }

   public WebResInfo getByIdsWithVehicleService(String requestBody) {
      return this.handler(RequestMethod.POST, "vehicle-service", "/v2/traffic/getTrafficByIds", requestBody);
   }

   public WebResInfo countVehicle(String condition) {
      return this.handler(RequestMethod.POST, "vehicle-service", "/vehicle/count", condition);
   }

   public WebResInfo listGcjl(String condition) {
      return this.handler(RequestMethod.POST, "vehicle-service", "/v2/traffic/list", condition);
   }

   public WebResInfo countWifi(String condition) {
      return this.handler(RequestMethod.POST, "wifi-service", "/wifi/count", condition);
   }

   public WebResInfo getNonmotoByRecordIds(NonmotorCondition condition) {
      return this.handler(RequestMethod.POST, "vehicle-service", "/nonmotor/get_by_recordIds", JSON.toJSONString(condition));
   }

   public WebResInfo getNonmotorList(String condition) {
      return this.handler(RequestMethod.POST, "vehicle-service", "/nonmotor/list", condition);
   }

   public WebResInfo countNonmotor(String condition) {
      return this.handler(RequestMethod.POST, "vehicle-service", "/nonmotor/count", condition);
   }

   public WebResInfo handler(RequestMethod method, String serviceId, String apiOrQueryUrl, final String body) {
      long startTime = System.currentTimeMillis();
      WebResInfo webResInfo = new WebResInfo();
      webResInfo.setCode("500");

      try {
         String serviceAddress = this.serviceAddress(serviceId);
         log.info("step 1 :{}", System.currentTimeMillis() - startTime);
         String url = serviceAddress + apiOrQueryUrl;
         log.info("dynamic feign client: {}|{}|{}", new Object[]{serviceId, url, body});
         Request.Builder builder = (new Request.Builder()).url(url);
         if (method == RequestMethod.GET) {
            builder.get();
         } else {
            if (method != RequestMethod.POST) {
               throw new UnsupportedOperationException("Not Support method " + method.name());
            }

            if (body == null) {
               throw new RuntimeException("Post request body must be not null.");
            }

            builder.post(new RequestBody() {
               public MediaType contentType() {
                  return MediaType.parse("application/json");
               }

               public void writeTo(BufferedSink sink) throws IOException {
                  sink.writeString(body, StandardCharsets.UTF_8);
                  sink.flush();
               }
            });
         }

         log.info("step 2 :{}", System.currentTimeMillis() - startTime);

         try {
            String data = this.call(builder.build());
            log.info("step 3 :{}", System.currentTimeMillis() - startTime);
            if (data != null) {
               webResInfo = (WebResInfo)JSON.parseObject(data, WebResInfo.class);
            }

            log.info("step 4 :{}", System.currentTimeMillis() - startTime);
         } catch (IOException var12) {
            log.error("Request exception .", var12);
         }
      } catch (ServiceInstanceFetchException var13) {
         log.error("Service address fetch from register center exception {}.", var13.getMessage());
      }

      log.warn("{}|{}请求时长：{}ms", new Object[]{serviceId, apiOrQueryUrl, System.currentTimeMillis() - startTime});
      return webResInfo;
   }

   private static class ServiceInstanceFetchException extends Exception {
      private ServiceInstanceFetchException() {
      }

      // $FF: synthetic method
/*      ServiceInstanceFetchException(Object x0) {
         this();
      }*/
   }
}
